/*
 *	Copyright © 2008 University of Houston
 *	All rights reserved.
 */

#include <inttypes.h>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include "gnuplotscript.h"
#include "gnuplotWriter.h"

using namespace std;

#define DEFAULT_FILTER		"0"
#define DEFAULT_ALG			"0"
#define DEFAULT_RES_FILTER	""
#define DEFAULT_OUTPUT		"data.dat"
#define DEFAULT_NORM_SIZE	"100"
#define FILE_DELIMITER		'@'
#define	FILE_DELIMITER_LONG	"long"
#define	FILE_DELIMITER_SHRT	"short"

void displayUsage(char **argv);
bool getParams(int argc, 
				char** argv,
				string *sessFilter, 
				string *alg,
				string *outfile, 
				string *normalize,
				string *resFilter,
				bool *usePoints, 
				bool *doExport, 
				int *verbose,
				bool *disablekey,
				vector<string> *logfiles,
				vector<string> *shortlogs,
				vector<string> *longlogs);

int main(int argc, char **argv)
{
	// Get all of our parameters
	vector<string> 	logfiles;
	vector<string>	shortLogs;
	vector<string>	longLogs;
	string 			outfile		= DEFAULT_OUTPUT;
	string 			filter		= DEFAULT_FILTER;
	string 			alg			= DEFAULT_ALG;
	string 			norm		= DEFAULT_NORM_SIZE;
	string			resFilter	= DEFAULT_RES_FILTER;
	bool 			usePoints	= false;
	bool 			doExport	= false;
	bool 			disableKey	= false;

	if( !getParams(argc, 
					argv, 
					&filter, 
					&alg, 
					&outfile, 
					&norm, 
					&resFilter,
					&usePoints, 
					&doExport, 
					&Trace::verbosity,
					&disableKey,
					&logfiles, 
					&shortLogs, 
					&longLogs) )
		return 1;

	// Convert some of the variables to number-types as needed
	int filterID			= strtol(filter.c_str());
	int algID				= strtol(alg.c_str());
	long double normalize 	= strtold(norm.c_str(),NULL);
	bool coalesceLogs		= (strchr(resFilter.c_str(), 'i') != NULL);

	// Load the data using the sessionAnalyzer class
	vector<analyzerResultList> normalResults, longResults, shortResults;
	sessionAnalyzer::recreate (&logfiles, &normalResults, filterID, algID);
	sessionAnalyzer::recreate (&longLogs, &shortResults, filterID, algID);
	sessionAnalyzer::recreate (&shortLogs, &longResults, filterID, algID);
	
	// Parse the pairs of results-filters into resFilterPair objects.
	vector<resFilterPair> res = resFilterPair::parseResFilters(resFilter);
	// Perform analysis/filtering on the results
	resultsAnalyzer ra(&res, &normalResults, &longResults, &shortResults);

	// Write the data to a data file
	gnuplotWriter w;
	w.normalize		= normalize;
	w.outfile		= outfile;
	w.fullResultList= *ra.getCompositeResults();
	if (!w.writeGnuplotData())
		return 1;

	// AutoGen the Gnuplot Script
	gnuplotScript g;
	g.usePoints  	= usePoints;
	g.doExport	 	= doExport;
	g.coalesceLogs	= coalesceLogs;
	g.outputFile 	= outfile;
	g.disableKey	= disableKey;
	g.fullResultList= *ra.getCompositeResults();
	g.miscLines		= *ra.getExtra();
	g.graphTitle	= filter::getFilterName(filterID) + "\\\\" +
						algorithm::getAlgName(algID);
						
	// Do not bother printing the title if we are not exporting to file.
	if (!g.doExport) 	g.graphTitle = "";
	
	g.writeScript();
	
	return 0;
}

/*
 * Checks the command-line arguments, and parses them into distinct vars.
 * @param argc 		[argc] as provided on the command-line.
 * @param argv 		[argv] as provided on the command-line.
 * @param sessFilt	Pointer to a string to store the session filter.
 * @param alg 		Pointer to a string to store the algorith number.
 * @param outfile	Output filename.
 * @param normalize	Normalization quantifier
 * @param usePoints	Choose whether to use points or just draw lines
 * @param doExport	Export the graph as a SVG
 * @param verbose		Verbose?
 * @param logfiles	Vector of log filenames
 * @param shortlogs	Vector of log filenames for short sessions
 * @param longlogs	Vector of log filenames for long sessions
 * @return 			False if there were not enough parameters provided.
 */
bool getParams(int argc, 
				char** argv,
				string *sessFilter, 
				string *alg,
				string *outfile, 
				string *normalize,
				string *resFilter, 
				bool *usePoints, 
				bool *doExport, 
				int *verbose,
				bool *disablekey,
				vector<string> *logfiles,
				vector<string> *shortlogs,
				vector<string> *longlogs)
{
	int index 	= 0;
	int c		= 0;
	opterr 		= 0;
	
	if( argc == 1 )
	{
		displayUsage(argv);
		return false;
	}
	
	while ((c = getopt (argc, argv, "f:o:a:n:r:epvhd?")) != -1)
		switch(c)
		{
			case 'a':	*alg 			= optarg;	break;
			case 'd':	*disablekey		= true;		break;
			case 'e':	*doExport 		= true;		break;
			case 'f':	*sessFilter 	= optarg;	break;
			case 'n':	*normalize 		= optarg;	break;
			case 'o':	*outfile 		= optarg;	break;
			case 'p':	*usePoints 		= true;		break;
			case 'r':	*resFilter		= optarg;	break;
			case 'v':	(*verbose)++;				break;
			
			default:
				ERROR("Option \'-" << optopt << "\' not supported.\n")
				// fprintf(stderr, "Option \'-%c\' not supported.\n", optopt);
			case 'h':	// see case '?'
			case '?':	displayUsage(argv);		return false;		
		}
		
	// ITERATE THROUGH ALL OF THE FILE NAMES
	bool bLong = false;
	bool bShort = false;
	for (index = optind; index < argc; index++)
	{
		// If the first character is a delimiter...
		if( argv[index][0] == FILE_DELIMITER )
		{
			// Check to see if we put a long delimiter.
			// @NOTE: The '+1' offset is to skip the FILE_DELIMITER character.			
			bLong 	= (strcmp(argv[index]+1, FILE_DELIMITER_LONG) == 0);
			bShort 	= (strcmp(argv[index]+1, FILE_DELIMITER_SHRT) == 0);

			if(bShort || bLong)
				continue;
		}

		// Add it to the right vector
		if(bShort)		shortlogs->push_back(argv[index]);
		else if(bLong)	longlogs->push_back(argv[index]);
		else			logfiles->push_back(argv[index]);
	}
	
	return true;
}

/*
 * Display the usage
 */
void displayUsage(char **argv)
{
	printf("Usage: %s [args] logfiles\n"
	"Supported Arguments: \n"
	"-a n       Log analyzer to use.     Default \'%s\'\n"
	"              0: No Analysis\n"
	"              1: Time Diff\n"
	"              2: Average\n"
	"              3: Standard Deviation\n"
	"              4: Uber (use Filter 0)\n"
	"-d         Disable key/legend\n"
	"-e         Export to svg file.\n"
	"-f n       Session filter to use.   Default \'%s\'\n"
	"              0: No Filter\n"
	"              1: Nearest Hop Filter\n"
	"              2: User Delay Filter\n"
	"              3: Encrypted In Filter\n"
	"              4: Encrypted Out Filter\n"
	"              5: Command Filter\n"
	"-r         List of results filters (comma deliminated)\n"
	"              c: Chomp Results\n"
	"              d: Mode of results\n"
	"              i: Criss Cross\n"
	"              g: Gap analysis\n"
	"              m: Median Result Value\n"
	"              r: Representative Result Value\n"
	"              s: Smooth Results\n"
	"              t: Sort Results\n"
	"-o path    Path to output file.     Default \'%s\'\n"
	"-n         Normalize xValues.       Default \'%s\'\n"
	"-p         Include points in graph.\n"
	"-v         Verbosity.  Specify twice for extra-verbose.\n"
	"-- LOG FILES --\n"
	"A space-delimited list of log files.  If you would like to specify    \n"
	"certain files as being a long-chain or short-chain, prefix the word   \n"
	"\'short\' or \'long\' with %c                                         \n"
	"Example:                                                              \n"
	"%s %cshort file1 file2 %clong file3 file4                             \n"
	"-- RESULT FILTERS --                                                  \n"
	"A comma-delimited list of results filters with their accompanying     \n"
	"values. Sort requires no value and will sort the results. Smooth      \n"
	"requires a parameter determining the smoothing. Chomp will remove the \n"
	"first n percent results. Median value will return a point representing\n"
	"the median of the data. Representitive Value will return a point      \n"
	"representing the dataset as a whole.                                  \n"
	"Example:                                                              \n"
	"%s -r c=0.5,m,r                                                       \n",
	argv[0], DEFAULT_ALG, DEFAULT_FILTER, DEFAULT_OUTPUT,
	DEFAULT_NORM_SIZE, FILE_DELIMITER, argv[0], FILE_DELIMITER, FILE_DELIMITER,
	argv[0]);
}

